import router from "./router";
import store from "./store";
import NProgress from "nprogress"; // progress bar
import notification from "ant-design-vue/es/notification";
import { getAccessToken } from "@/utils/tokenUtils/accessTokenCache";

NProgress.configure({ showSpinner: false }); // NProgress Configuration

const allowList = ["login", "register", "registerResult"]; // no redirect allowList
const loginRoutePath = "/login";
const defaultRoutePath = "/home";

/**
 * to: Route: 即将要进入的目标 路由对象
 * from: Route: 当前导航正要离开的路由
 * next: Function: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数
 * next(): 进行管道中的下一个钩子。如果全部钩子执行完了，则导航的状态就是 confirmed (确认的)。
 * next(false): 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮)，那么 URL 地址会重置到 from 路由对应的地址
 * next('/') 或者 next({ path: '/' }): 跳转到一个不同的地址。当前的导航被中断，然后进行一个新的导航。你可以向 next 传递任意位置对象，且允许设置诸如 replace: true、name: 'home' 之类的选项以及任何用在 router-link 的 to prop 或 router.push 中的选项
 * next(error): (2.4.0+) 如果传入 next 的参数是一个 Error 实例，则导航会被终止且该错误会被传递给 router.onError() 注册过的回调
 * 确保要调用 next 方法，否则钩子就不会被 resolved
 */
router.beforeEach((to, from, next) => {
  NProgress.start();
  // 获取token
  let token = getAccessToken();
  // token存在
  if (token) {
    if (to.path === loginRoutePath) {
      next({ path: defaultRoutePath });
      NProgress.done();
    } else {
      if (store.getters.roles.length === 0) {
        store
          .dispatch("getUserInfo")
          .then((res) => {
            const roles = res.data && res.data.role;
            // generate dynamic router
            store.dispatch("generateRoutes", { roles }).then(() => {
              // 根据roles权限生成可访问的路由表
              // 动态添加可访问路由表
              store.getters.addRouters.forEach((route) => {
                router.addRoute(route);
              });
              // router.addRoutes(store.getters.addRouters)
              // 请求带有 redirect 重定向时，登录自动重定向到该地址
              const redirect = decodeURIComponent(
                from.query.redirect || to.path
              );
              if (to.path === redirect) {
                next({ ...to, replace: true }); // set the replace: true so the navigation will not leave a history record
              } else {
                // 跳转到目的路由
                next({ path: redirect });
              }
            });
          })
          .catch((error) => {
            // notification.error({
            //   message: '错误',
            //   description: '请求用户信息失败，请重试:' + error
            // })
            // 失败时，获取用户信息失败时，调用登出，来清空历史保留信息
            store.dispatch("logout").then(() => {
              next({ path: loginRoutePath, query: { redirect: to.fullPath } });
            });
          });
      } else {
        next();
      }
    }
  } else {
    if (allowList.includes(to.name)) {
      // 在免登录名单，直接进入
      next();
    } else {
      // 跳转到登录界面
      next({ path: loginRoutePath, query: { redirect: to.fullPath } });
      NProgress.done();
    }
  }
});

router.afterEach(() => {
  NProgress.done();
});

// 解决Loading chunk (\d)+ failed问题
router.onError((error) => {
  const pattern = /Loading chunk (\d)+ failed/g;
  const isChunkLoadFailed = error.message.match(pattern);
  if (isChunkLoadFailed) {
    // 用路由的replace方法，并没有相当于F5刷新页面，失败的js文件并没有从新请求，会导致一直尝试replace页面导致死循环，
    // const targetPath = router.history.pending.fullPath;
    // router.replace(targetPath);
    // 而用 location.reload 方法，相当于触发F5刷新页面，虽然用户体验上来说会有刷新加载察觉，但不会导致页面卡死及死循环
    location.reload();
  }
});
